#pragma once
#include <string>
#include <functional>
#include <queue>
#include "curl/curl.h"
#include "poller.h"
#include "../common/timer.h"
#include "HttpData.h"




using HttpResponseCb = std::function<void(std::uint64_t id, int err, stHttpResponse&&)>;

class CurlClient;
class CurlHandler : public CPollerObject
{
    friend class CurlClient;
public:
    CurlHandler(CurlClient* client);
    virtual ~CurlHandler();
    void Reset(const std::string& url = "");

public:
    int Run(stHttpRequest&& http_req, stHttpResponse& http_resp);
    int RunAsync(stHttpRequest&& http_req);

public:
    inline void SetReqID(std::uint64_t req_id)
    {
        m_req_id = req_id;
    }
    
protected:
    void SetCommon(bool keepalive = false);
    void SetRequset(stHttpRequest&& req);
    void ActivePoll(int fd);

protected:
    // poller
	virtual int Init();
	virtual int InputNotify();
	virtual int OutputNotify();
	virtual int HangupNotify();

    inline int ID() const {
        return netfd;
    }

private:
    CURL *m_curl = NULL;
    char m_error[CURL_ERROR_SIZE];
    struct curl_slist* m_head = NULL;
    stHttpRequest m_http_req;
    stHttpResponse m_http_resp;
    CurlClient* m_client = NULL;
    std::uint64_t m_req_id;
};

class CurlClient : public TimerOutEvent
{
    friend class CurlHandler;
public:

public:
    CurlClient();
    virtual ~CurlClient();

public:
    bool Initialize();

public:
    virtual int Request(stHttpRequest&& http_req, stHttpResponse& http_resp);
    virtual int RequestAsync(std::uint64_t uuid, stHttpRequest&& http_req);

    inline void SetResponseCb(HttpResponseCb && cb) 
    {
        m_resp_cb = std::move(cb);
    }

protected:
    void CacheRequest(std::uint64_t uuid, stHttpRequest&& http_req);
    int RequestAsync(CurlHandler* curl_handler, std::uint64_t uuid, stHttpRequest&& http_req);
    virtual void ResetHandler(CurlHandler* curl_handler);

protected:
    static int socketCallback(CURL *curl, curl_socket_t s, int what, void *userp, void *socketp);
    static int timeoutCallback(CURLM *m_pMulti, long timeout_ms, CurlClient *client);

protected:
    // timer
	virtual int ProcessOnTimerOut(int Timerid);
    int ProcessOnEvent(int fd, int event);

    void check_multi_info();
    void OnResponse(std::uint64_t id, int err, stHttpResponse&& response);
    
protected:
    virtual CurlHandler* AllocHandler();
    virtual void RecycleHandler(CurlHandler* handler);

private:
    CCTimer m_timer;
    CURLM* m_pMulti = NULL;
    int m_still_running = true;
    HttpResponseCb m_resp_cb;
    std::int32_t m_requestCount = 0;
    std::queue<stHttpRequestQueueItem> m_request_list;
    int m_timer_id = -1;
    static std::int64_t m_active_client;
};

class CurlProxy : public CurlClient
{
public:
    explicit CurlProxy(const std::string& url, bool keepalive);
    virtual ~CurlProxy();

public:
    virtual int Request(stHttpRequest&& http_req, stHttpResponse& http_resp);
    virtual int RequestAsync(std::uint64_t uuid, stHttpRequest&& http_req);

protected:
    virtual void ResetHandler(CurlHandler* curl_handler);
    bool CheckRequest(stHttpRequest& http_req) const;

private:
    std::string m_url;
    bool m_keepalive;
};









